﻿//
// ParallelGrep
//
// Copyright (C) 2011 - Tatsuya Niioka
//
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Win32;
using ParallelGrep.Model;
using System.IO;
using System.Drawing;
using System.Windows;
using System.Windows.Media.Imaging;
using System.Runtime.InteropServices;

namespace ParallelGrep.Utility
{
    /// <summary>
    /// レジストリキーヘルパークラス
    /// </summary>
    public sealed class RegistryHelper
    {
        #region GetOpenProgram
        /// <summary>
        /// 指定したファイル名で、レジストリ―からファイルを開くプログラム情報を取得します。
        /// </summary>
        /// <param name="fileName">ファイル名</param>
        /// <returns>プログラム情報</returns>
        internal static string GetOpenProgram(string fileName)
        {
            const string registryBaseKey = @"Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\{0}\UserChoice";
            string regKey = string.Format(registryBaseKey, Path.GetExtension(fileName));
            using (RegistryKey key = Registry.CurrentUser.OpenSubKey(regKey))
            {
                if (key == null)
                {
                    return null;
                }
                List<string> programs = new List<string>();
                string[] names = key.GetValueNames();
                string program = (string)key.GetValue(names[0]);

                using (RegistryKey application = Registry.ClassesRoot.OpenSubKey(program))
                {
                    if (application == null)
                    {
                        return null;
                    }
                    using (RegistryKey command = application.OpenSubKey("shell\\open\\command"))
                    {
                        if (command == null)
                        {
                            return null;
                        }
                        return (string)command.GetValue("");
                    }
                }
            }
        }
        #endregion

        #region GetEditProgram
        /// <summary>
        /// 指定したファイル名で、ファイルを編集するプログラム情報を取得します。
        /// </summary>
        /// <param name="fileName">ファイル名</param>
        /// <returns>プログラム情報</returns>
        internal static string GetEditProgram(string fileName)
        {
            const string registryBaseKey = @"Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\{0}\UserChoice";
            string regKey = string.Format(registryBaseKey, Path.GetExtension(fileName));
            using (RegistryKey key = Registry.CurrentUser.OpenSubKey(regKey))
            {
                if (key == null)
                {
                    return null;
                }
                List<string> programs = new List<string>();
                string[] names = key.GetValueNames();
                string program = (string)key.GetValue(names[0]);

                using (RegistryKey application = Registry.ClassesRoot.OpenSubKey(program))
                {
                    if (application == null)
                    {
                        return null;
                    }
                    using (RegistryKey command = application.OpenSubKey("shell\\edit\\command"))
                    {
                        if (command == null)
                        {
                            return null;
                        }
                        return (string)command.GetValue("");
                    }
                }
            }
        }
        #endregion

        public static string GetEditorProgram()
        {
            List<MenuInfo<string>> list = new List<MenuInfo<string>>();
            const string registryBaseKey = @"Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\{0}";
            string regKey = string.Format(registryBaseKey, Path.GetExtension(".txt"));

            using (RegistryKey key = Registry.CurrentUser.OpenSubKey(regKey))
            {
                if (key == null)
                {
                    return null;
                }
                string[] files = GetOpenWithList(key);
                foreach (string file in files)
                {
                    string programFile = GetApplicationShellCommand(file);
                    if (programFile != null)
                    {
                        return programFile;
                    }
                }
            }
            return null;
        }

        #region GetOpenWithList
        /// <summary>
        /// 指定したファイル名からメニュー一覧を取得します。
        /// </summary>
        /// <param name="fileName">ファイル名</param>
        /// <returns>メニュー一覧</returns>
        public static MenuInfo<string>[] GetOpenWithList(string fileName)
        {
            List<MenuInfo<string>> list = new List<MenuInfo<string>>();
            const string registryBaseKey = @"Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\{0}";
            string regKey = string.Format(registryBaseKey, Path.GetExtension(fileName));

            using (RegistryKey key = Registry.CurrentUser.OpenSubKey(regKey))
            {
                if (key == null)
                {
                    return null;
                }
                string[] files = GetOpenWithList(key);
                foreach (string file in files)
                {
                    string programFile = GetApplicationShellCommand(file);
                    if (programFile != null)
                    {
                        string[] cmd = StringHelper.Split(programFile);
                        FileInfo info = new FileInfo(cmd[0].Replace("\"", ""));
                        if (info.Exists)
                        {
                            BitmapSource bitmapSource = GetBitmapSource(info.FullName);

                            MenuInfo<string> menu = new MenuInfo<string>(info.Name.Replace(info.Extension, ""), programFile, bitmapSource);
                            list.Add(menu);
                        }
                    }
                }

                string[] progIds = GetOpenWithProgIds(key);
                foreach (var id in progIds)
                {
                    using (RegistryKey regKeyId = Registry.ClassesRoot.OpenSubKey(id))
                    {
                        if (regKeyId == null)
                        {
                            break;
                        }
                        string programFile = (string)regKeyId.GetValue("");
                        if (programFile != null)
                        {
                            string[] cmd = StringHelper.Split(programFile);
                            FileInfo info = new FileInfo(cmd[0].Replace("\"", ""));
                            if (info.Exists)
                            {
                                BitmapSource bitmapSource = GetBitmapSource(info.FullName);

                                MenuInfo<string> menu = new MenuInfo<string>(info.Name.Replace(info.Extension, ""), programFile, bitmapSource);
                                list.Add(menu);
                            }
                        }
                    }
                }
            }
            return list.ToArray();
        }
        #endregion

        #region GetBitmapSource
        /// <summary>
        /// 指定したファイル名で、ビットマップソースを取得します。
        /// </summary>
        /// <param name="fileName">ファイル名</param>
        /// <returns>ビットマップソース</returns>
        public static BitmapSource GetBitmapSource(string fileName)
        {
            Icon icon = ExtractIcon.GetSelectedIcon(fileName, true);
            return System.Windows.Interop.Imaging.CreateBitmapSourceFromHIcon(
                           icon.Handle, Int32Rect.Empty,
                           BitmapSizeOptions.FromEmptyOptions());
        }
        #endregion

        #region GetApplicationShellCommand
        /// <summary>
        /// 指定したファイル名で、アプリケーションシェルコマンドを取得します。
        /// </summary>
        /// <param name="fileName">ファイル名</param>
        /// <returns>アプリケーションシェルコマンド</returns>
        public static string GetApplicationShellCommand(string fileName)
        {
            const string registryKey = @"Applications\{0}\shell\open\command";
            string regKey = string.Format(registryKey, fileName);
            //HKEY_CLASSES_ROOT\Applications
            using (RegistryKey cmd = Registry.ClassesRoot.OpenSubKey(regKey))
            {
                if (cmd == null)
                {
                    return null;
                }
                return (string)cmd.GetValue("");
            }
        }
        #endregion

        #region GetOpenWithList
        /// <summary>
        /// 指定したレジストリキーからオープンリストを取得します。
        /// </summary>
        /// <param name="registryKey">レジストリキー</param>
        /// <returns>オープンリスト</returns>
        public static string[] GetOpenWithList(RegistryKey registryKey)
        {
            using (RegistryKey openWithListKey = registryKey.OpenSubKey("OpenWithList"))
            {
                if (openWithListKey == null)
                {
                    return null;
                }
                string MRUList = (string)openWithListKey.GetValue("MRUList");
                if (MRUList == null)
                {
                    return null;
                }
                List<string> programs = new List<string>();
                foreach (char c in MRUList)
                {
                    string program = (string)openWithListKey.GetValue(c.ToString());
                    programs.Add(program);
                }
                return programs.ToArray();
            }
        }
        #endregion

        #region GetOpenWithProgIds
        /// <summary>
        /// 指定したレジストリキーからプログラムID一覧を取得します。
        /// </summary>
        /// <param name="registryKey">レジストリキー</param>
        /// <returns>プログラムID一覧</returns>
        public static string[] GetOpenWithProgIds(RegistryKey registryKey)
        {
            using (RegistryKey openWithProgids = registryKey.OpenSubKey("OpenWithProgids"))
            {
                if (openWithProgids == null)
                {
                    return null;
                }
                List<string> programs = new List<string>();
                string[] names = openWithProgids.GetValueNames();
                foreach (string name in names)
                {
                    programs.Add(name);
                }
                return programs.ToArray();
            }
        }
        #endregion
    }
}
